#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>
#include "process.h"

using namespace std;

//  Constructor for Process
Process::Process(char icode_loc [256]) {
  ptick = -1; // Set to 0 on first run()
  //  mmu = immu // Now done through addMMu(MMU* immu)

  strcpy (code_loc, icode_loc); // Name of file containing code
  //create empty process page table.
  pt = new PageTable();

  // Open trace file
  f = NULL;
  f = fopen(code_loc, "r");

  if (f == NULL) {
    cout << "ERROR: File not found: " << code_loc << endl;
    exit(1);
  }
}

int Process::run(int tick) {
  ptick++;

  cout << "Ptick: " << ptick << endl;

  // Run the Daemon
  if (ptick % N == 0 && ptick != 0) mmu->daemon(ptick, tick);

  // Allocate memory to hold a line from trace
  char line[256];
  if (line == NULL) {
    cout << "Out of memory" << endl;
    exit(1);
  }

  if (fgets (line, 256, f) != NULL) {
    cout << "Line: " << line;
    stringstream ss(line);
    char c;
    int val;

    ss >> c >> val;

    // Process VA if in hex
    if (val == 0) {
      char c1; string s; stringstream ss_hex; // Catch 'x' in hex
      ss >> c1 >> s;
      ss_hex << hex << s;
      ss_hex >> val;
      //cout << val << endl;
    }

    cout << "Executing " << c << " " << val << endl;

    int result;

    switch (c) {
    case 'R':
    case 'r':
      // If using Working Set, send ptick instead of tick
      if (mmu->getPolicy() == PG_WORKINGSET) {
	result = mmu->findAddress(true, val, base, bound, ptick);
      } else {
	result = mmu->findAddress(true, val, base, bound, tick);
      }
      break;
    case 'W':
    case 'w':
      // If using Working Set, send ptick instead of tick
      if (mmu->getPolicy() == PG_WORKINGSET) {
        result = mmu->findAddress(false, val, base, bound, ptick);
      } else {
	result = mmu->findAddress(false, val, base, bound, tick);
      }
      break;
    default:
      cout << "Instruction begins without R or W" << endl;
      exit(1);
    }

    switch (result) {
    case PRA_CLEAN:
      return PRET_PAGE_FAULT;
      break; // useless
    case PRA_DIRTY:
      return PRET_PAGE_FAULT_DIRTY;
      break; // useless
    case 0:
    default:
      return PRET_SUCCESS;
      break;
    }

  } else {
    cout << "EOF" << endl;
    return PRET_END_PROCESS;
  }

  // Shouldn't reach this line
  return PRET_ERROR;
}

// Clean up after Process
void Process::close() {
  fclose(f);
}

